package obecto.core
{
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	
	import obecto.event.FLEvent;
	import obecto.event.LayoutEvent;
	import obecto.layout.ILayout;
	
	[Bindable]
	[DefaultProperty("contentChildren")]
	public class FLContainer extends FLUIComponent
	{
		public var waitChildrenCreationComplete : Boolean = true;
		
		private var _layout : ILayout;
        public function get layout():ILayout
        {
            return _layout;
        }

        public function set layout(value:ILayout):void
        {
            if (!value || value == _layout) return;
            
            if (_layout) 
            {
                _layout.removeEventListener(LayoutEvent.LAYOUT_UPDATE, handleLayoutUpdate);
            }
            
            _layout = value;
            
            if (_layout) 
            {
                _layout.addEventListener(LayoutEvent.LAYOUT_UPDATE, handleLayoutUpdate);
            }
        }

		/**
		 * If you want to use a part in the asset for a contentPane instead of the container itself, 
		 * you just need to add the following metadata:
		 * [Part(name="contentPane", path="path.to.the.contentPane")]
		 */ 
		public var contentPane : Sprite;
		
	    protected var _contentChildren : Array;
		public function set contentChildren(value : Array) : void 
 		{
			if (value != null && value != _contentChildren)
			{
				if (_contentChildren != null)
				{
					removeContentChildren();
					disposeContentChildren();
					contentChildrenInitialized = false;
				}
 	
				_contentChildren = value;
				initializeContentChildren();
			}
		}
		public function get contentChildren() : Array
		{
			return _contentChildren;
		}
		
		protected function get allChildrenInitialized() : Boolean
		{
			var result : Boolean = true;
			for each (var child : DisplayObject in _contentChildren)
			{
				if (child is FLUIComponent)
				{
					if (!FLUIComponent(child).initialized)
					{
						result = false;
						break;
					}
				}
			}
			return result;
		}
		
		protected var contentChildrenInitialized : Boolean = false;
		
		public function FLContainer()
		{
			super();
			
			contentPane = this;
		}
		
		protected function initializeContentChildren() : void  
		{
			if (contentChildrenInitialized || !partsInitialized)
			{
				return;
			}
			
			if (_contentChildren != null)
			{
				addContentChildren();
				contentChildrenInitialized = true;
				
				if (layout != null)
				{
					layout.items = _contentChildren;
				}
			}
		}
		
		protected function addContentChildren() : void 
		{
			for each (var child : DisplayObject in _contentChildren)
			{
				addContentChild(child, true);
			}
		}
		
		protected function removeContentChildren() : void 
		{
			for each (var child : DisplayObject in _contentChildren)
			{
				removeContentChild(child);
			}
		}
		
		protected function addContentChild(child : DisplayObject, alreadyContentChild : Boolean = false) : void 
		{	
			if (!alreadyContentChild)
				_contentChildren.push(child);
			
			if (child is FLUIComponent)
			{
				if (FLUIComponent(child).initialized)
				{
					contentPane.addChild(child);
				}
				else
				{
					FLUIComponent(child).addEventListener(FLEvent.CREATION_COMPLETE, handleFLUIComponentCreationComplete);
				}
			}
			else
			{
				contentPane.addChild(child);
			}
		}
		
		protected function removeContentChild(child : DisplayObject) : void 
		{
			contentPane.removeChild(child);
			if (child is FLUIComponent && 
				FLUIComponent(child).hasEventListener(FLEvent.CREATION_COMPLETE))
			{
				FLUIComponent(child).removeEventListener(FLEvent.CREATION_COMPLETE, handleFLUIComponentCreationComplete);
			}
		}
		
		/**
		 * Abstract method to give you an opportunity to hook into if you 
		 * need some special cleaning logic, e.g. removing event listeners, etc.
		 */ 
		virtual protected function disposeContentChildren() : void 
		{
			return;
		}
		
		/**
		 * Abstract method to give you an opportunity to hook into if you 
		 * need to handle logic that is triggered right after layout update.
		 */ 
        virtual protected function layoutUpdate() : void
        {
			return;
        }
		
		override protected function initializeParts() : void
		{
			super.initializeParts();
		}
		
		override protected function initialize() : void
		{
			initializeContentChildren();
		}
		
		protected function creationComplete() : void 
		{
			initialized = true;
			dispatchEvent(new FLEvent(FLEvent.CREATION_COMPLETE));
		}
		
		override protected function handleEnterFrame(e : Event) : void
		{
			FLGlobals.topLevelSprite.removeEventListener(Event.ENTER_FRAME, handleEnterFrame);
			
			initializeParts();
			initializeDimensions(); // set the preinitialize width and height
			initialize(); // perform custom initialization:
			
			if (waitChildrenCreationComplete)
			{
				if (allChildrenInitialized)
				{
					creationComplete();
				}
			}
			else
			{
				creationComplete();
			}
		}
		
		protected function handleFLUIComponentCreationComplete(e : FLEvent) : void 
		{
			var child : DisplayObject = DisplayObject(e.target);
			
			var childIndex : int =  _contentChildren.indexOf(child);
			var currentChildIndex : int;
			
			for (var i : int = 0; i < contentPane.numChildren; i++)
			{
				currentChildIndex = _contentChildren.indexOf(contentPane.getChildAt(i));
				if (childIndex < currentChildIndex)
				{
					break;
				}
			}
            
			contentPane.addChildAt(child, i);
			
			if (waitChildrenCreationComplete)
			{
				if (allChildrenInitialized)
				{
					creationComplete();
				}
			}
		}
		
        private function handleLayoutUpdate(e:LayoutEvent) : void
        {
            e.stopImmediatePropagation();
            layoutUpdate();   
        }
	}
}